package com.candy.biz.service.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.ObjectUtil;
import com.candy.biz.domain.entity.SysRole;
import com.candy.biz.domain.entity.SysRoleMenu;
import com.candy.biz.domain.param.SysRoleAssigningMenusParam;
import com.candy.biz.domain.param.SysRoleQueryParam;
import com.candy.biz.domain.param.SysRoleSaveParam;
import com.candy.biz.domain.vo.SysRoleVO;
import com.candy.biz.enums.RoleTypeEnum;
import com.candy.biz.manager.SysRoleManager;
import com.candy.biz.mapper.SysRoleMapper;
import com.candy.biz.mapper.SysRoleMenuMapper;
import com.candy.biz.service.SysRoleService;
import com.candy.common.domain.PageVO;
import com.candy.common.enums.AdminErrorEnum;
import com.candy.common.utils.Assert;
import com.candy.common.utils.CommonUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.If;
import com.mybatisflex.core.query.QueryChain;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import lombok.AllArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

import static com.candy.biz.domain.entity.table.SysRoleMenuTableDef.SYS_ROLE_MENU;
import static com.candy.biz.domain.entity.table.SysRoleTableDef.SYS_ROLE;


/**
 * 系统角色-服务层实现。
 *
 * @author rong xi
 * @date 2023/09/18 09:18
 * @version 1.0.0
 */
@Service
@AllArgsConstructor
@Slf4j
public class SysRoleServiceImpl extends ServiceImpl<SysRoleMapper, SysRole> implements SysRoleService {
    private final SysRoleMenuMapper sysRoleMenuMapper;

    /**
     * 查询系统角色详情
     *
     * @param id 系统角色id
     * @return 详情VO
     */
    @Override
    public SysRoleVO queryInfo(Long id) {
        return this.getByIdOpt(id).map(SysRoleManager::poToVo).orElse(null);
    }

    /**
     * 分页查询系统角色
     *
     * @param param 查询参数
     * @return 分页结果
     */
    @Override
    public PageVO<SysRoleVO> queryPage(SysRoleQueryParam param) {
        Page<SysRole> page = queryChain()
                .select(SYS_ROLE.ALL_COLUMNS)
                .from(SYS_ROLE)
                .where(SYS_ROLE.ROLE_CODE.like(param.getRoleCode(), If::hasText))
                .and(SYS_ROLE.ROLE_NAME.like(param.getRoleName(), If::hasText))
                .and(SYS_ROLE.ID.eq(param.getId(),If::notNull))
                .orderBy(param.getOrderBy(SYS_ROLE))
                .page(param.getPage());
        return SysRoleManager.pageToPageVO(page);
    }

    /**
     * 根据查询条件导出系统角色
     *
     * @param param 查询参数
     */
    @Override
    @SneakyThrows
    public void export(SysRoleQueryParam param) {
        //修改分页条件
        param.preparationExport();
        //查询数据
        List<SysRoleVO> rows = queryPage(param).getList();
        //导出文件
        CommonUtil.exportExcel("系统角色",rows,SysRoleVO.class);
    }

    /**
     * 保存系统角色
     *
     * @param param 保存参数
     * @return 保存结果
     */
    @Override
    public Boolean saveHandle(SysRoleSaveParam param) {
        return CommonUtil.<SysRoleSaveParam,Boolean>predicateFunction(param,
                (p)-> ObjectUtil.isNull(p.getId()),
                (p)->this.save(SysRoleManager.insertPrepare(p)),
                (p)-> this.updateById(SysRoleManager.updatePrepare(p)));
    }

    /**
     * 根据条件查询角色列表
     *
     * @param param 查询参数
     * @return 角色列表
     */
    @Override
    public List<SysRoleVO> queryList(SysRoleQueryParam param) {
        List<SysRole> list = queryChain()
                .select(SYS_ROLE.ALL_COLUMNS)
                .from(SYS_ROLE)
                .where(SYS_ROLE.ROLE_CODE.like(param.getRoleCode(), If::hasText))
                .and(SYS_ROLE.ROLE_NAME.like(param.getRoleName(), If::hasText))
                .and(SYS_ROLE.ID.eq(param.getId(), If::notNull))
                .orderBy(param.getOrderBy(SYS_ROLE))
                .list();
        return SysRoleManager.posToVos(list);
    }

    /**
     * 保存角色分配的菜单
     * @param param 保存参数
     * @return 保存结果
     */
    @Override
    public Boolean assigningMenu(SysRoleAssigningMenusParam param) {
        long userId = StpUtil.getLoginIdAsLong();
        LocalDateTime now = LocalDateTime.now();
        //1.删除旧数据
        sysRoleMenuMapper.deleteByCondition(SYS_ROLE_MENU.ROLE_ID.eq(param.getRoleId()));
        //2.插入新数据
        Optional.ofNullable(param.getMenuIds())
                .filter(CollectionUtil::isNotEmpty)
                .map(l->l.stream()
                        .map(mid->SysRoleMenu.builder()
                            .id(IdUtil.getSnowflakeNextId())
                            .roleId(param.getRoleId())
                            .menuId(mid)
                            .createTime(now)
                            .createUser(userId)
                            .build())
                        .collect(Collectors.toList()))
                .ifPresent(sysRoleMenuMapper::insertBatch);
        return true;
    }

    /**
     * 查询已分配的菜单权限
     *
     * @param id 角色id
     * @return id列表
     */
    @Override
    public List<Long> queryAssignedMenu(Long id) {
        return QueryChain.of(sysRoleMenuMapper)
                .select(SYS_ROLE_MENU.MENU_ID)
                .from(SYS_ROLE_MENU)
                .where(SYS_ROLE_MENU.ROLE_ID.eq(id))
                .listAs(Long.class);
    }

    /**
     * 删除角色
     *
     * @param id 角色id
     * @return 删除结果
     */
    @Override
    public Boolean removeRole(Long id) {
        SysRole sysRole = this.getById(id);
        Assert.notNull(sysRole, AdminErrorEnum.ROLE_NOT_EXISTS);
        Assert.notEquals(RoleTypeEnum.SYSTEM.getValue(),sysRole.getType(),AdminErrorEnum.SYSTEM_ROLE_CANT_NOT_DELETE);
        //删除角色
        return removeById(id);
    }
}
